package com.hqyj.springBoot.modules.common.controller;

import com.hqyj.springBoot.modules.common.entity.ExceptionLog;
import com.hqyj.springBoot.modules.common.service.ExceptionLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class ExceptionHandleController {

    @Autowired
    private ExceptionLogService exceptionLogService;
    private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandleController.class);


    /**
     *
     * @param request 获取请求信息
     * @param exception 获取异常信息
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    //页面调用返回页面，接口调用返回对象，所以使用ModelAndView作为返回值
    //返回MappingJackson2View
    public ModelAndView exceptionHandle(HttpServletRequest request,
                                        Exception exception){

        //输出异常日志
        exception.printStackTrace();
        LOGGER.debug(exception.getMessage());

        //构建返回数据
        int code = 200;
        String message = "";
        String data = "";

        //暂时将算术异常作为没有权限处理
        if (exception instanceof ArithmeticException){
            code = 403;
            message = "没有权限";
            data = "/common/403";
        }else {
            code = 500;
            message = "内部错误";
            data = "/common/500";
        }

        //保存异常信息到数据库
        insertExceptionLog(request,exception);

        //判断是否为接口?
        if (isApi(request)){
            //是接口,返回不同的ModelAndView
            ModelAndView md = new ModelAndView(new MappingJackson2JsonView());
            md.addObject("status",code);
            md.addObject("message",message);
            md.addObject("data",data);
            return md;
        }else {
            //不是接口，返回到对应的错误页面
            ModelAndView md = new ModelAndView("redirect:" + data);
            return md;
        }

    }

    public boolean isApi(HttpServletRequest request){
        HandlerMethod handlerMethod = (HandlerMethod) request.
                getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");
        RestController[] result1 = handlerMethod.getBeanType().
                getDeclaredAnnotationsByType(RestController.class);
        ResponseBody[] result2 = handlerMethod.getBeanType().
                getDeclaredAnnotationsByType(ResponseBody.class);
        ResponseBody[] result3 = handlerMethod.getMethod().
                getDeclaredAnnotationsByType(ResponseBody.class);
        return result1.length > 0 || result2.length > 0 || result3.length > 0;
    }

    public void insertExceptionLog(HttpServletRequest request,
                                   Exception exception){
        //保存异常信息到数据库
        ExceptionLog el = new ExceptionLog();
        el.setIp(request.getRemoteAddr());//拿到ip地址
        el.setPath(request.getServletPath());//拿到访问路径

        //这一步通过request的attributes来拿到!!!重要!学!!!
        HandlerMethod handlerMethod = (HandlerMethod) request.
                getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");

        el.setClassName(handlerMethod.getBeanType().getSimpleName());
        el.setMethodName(handlerMethod.getMethod().getName());
        el.setExceptionType(exception.getClass().getName());
        el.setExceptionMessage(exception.getMessage());

        exceptionLogService.insertExceptionLog(el);
    }

}
